package cn.com.utt.unms.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.alibaba.fastjson.JSON;
import cn.com.utt.common.exception.RPCException;
import cn.com.utt.common.http.Client;
import cn.com.utt.common.log.doLog;
import cn.com.utt.common.message.Message;
import cn.com.utt.common.message.Set;
import cn.com.utt.common.proto.RfConfig;
import cn.com.utt.common.protorpc.RPCClient;
import cn.com.utt.common.util.Token;
import cn.com.utt.common.util.LocaleMessageSourceUtil;
import cn.com.utt.common.util.MqttDeviceClientConfig;
import cn.com.utt.common.util.Tips;
import cn.com.utt.common.vo.RestResult;
import cn.com.utt.common.vo.TableInput;
import cn.com.utt.common.vo.TableOutput;
import cn.com.utt.common.zk.HttpDNSDiscovery;
import cn.com.utt.unms.mapper.RfMapper;
import cn.com.utt.unms.mapper.DeviceMapper;
import cn.com.utt.unms.mapper.CustomRfMapper;
import cn.com.utt.unms.pojo.Device;
import cn.com.utt.unms.pojo.CustomRf;
import cn.com.utt.unms.pojo.RfCommon;
import cn.com.utt.unms.service.RfService;
import cn.com.utt.unms.vo.RfInput;
import cn.com.utt.unms.pojo.Rf;

@Service("rfService")
public class RfServiceImpl implements RfService {
	
	@Autowired
    private LocaleMessageSourceUtil messageSourceUtil;

	@Autowired
	private RfMapper rfMapper;

	@Autowired
	private DeviceMapper deviceMapper;

	@Autowired
	private CustomRfMapper customRfMapper;

	@Autowired
	private RPCClient rpcClient;
	
	@Autowired
	private HttpDNSDiscovery httpDNSDiscoery;

	@Override
	public List<Rf> queryRfsByUserID(long userId) {
		return rfMapper.queryRfsByUserID(userId);
	}

	/**
	 * @return 检查设备射频配置格式是否正确
	 */
	private boolean checkRf(long userId, Rf rf) {
		if (rf != null) {
			long id = rf.getId();
			if (id <= 0) {
				id = (long) 0;
				rf.setId(id);
			}
			return true;
		}
		return false;
	}

	/**
	 * 要下发的射频数据
	 * 
	 * @param rf
	 * @return
	 */
	private Map<String, Object> saveParams(RfCommon rf) {
		Map<String, Object> params = new HashMap<String, Object>();
		List<RfConfig> list = new ArrayList<RfConfig>();
		RfConfig r1 = new RfConfig();
		RfConfig r2 = new RfConfig();
		// 2.4G
		r1.setRfIndex(1);
		r1.setBandwidth(rf.getG24Bandwidth());
		r1.setBeaconInterval(rf.getG24BeaconInterval());
		r1.setChannel(rf.getG24Channel());
		r1.setEnable(rf.getG24En());
		r1.setPreamble(rf.getG24ShortPreamble());
		r1.setRadio(1);
		r1.setRfMode(rf.getG24Standard());
		r1.setRfRate(rf.getG24Bitrate());
		r1.setRoamingThreshold(rf.getG24Roamingthreshold());
		r1.setShortGI(rf.getG24ShortInterval());
		// r1.setTxPower(rf.getG24PowerLevel());
		if (rf.getG24PowerMode() == 0) {
			r1.setTxPower(rf.getG24PowerMode());
		} else {
			r1.setTxPower(rf.getG24PowerLevel());
		}
		// r1.setvChanWidth(rf.getG5VhtBandwidth());
		r1.setWmm(rf.getG24WmmEn());
		// r1.setRelateThreshold(rf.getG24WmmRelate());
		r1.setClients(rf.getG24Clients());
		// 5G
		r2.setRfIndex(1);
		r2.setBandwidth(rf.getG5Bandwidth());
		if (rf.getG5PowerMode() == 0) {
			r2.setTxPower(rf.getG5PowerMode());
		} else {
			r2.setTxPower(rf.getG5PowerLevel());
		}
		// r2.setTxPower(rf.getG5PowerLevel());
		r2.setBeaconInterval(rf.getG5BeaconInterval());
		if (rf.getG5Standard() > 4) {
			r2.setvChanWidth(rf.getG5VhtBandwidth());
		}
		r2.setRadio(2);
		r2.setChannel(rf.getG5Channel());
		r2.setEnable(rf.getG5En());
		r2.setPreamble(rf.getG5ShortPreamble());
		r2.setRfMode(rf.getG5Standard());
		r2.setRoamingThreshold(rf.getG5Roamingthreshold());
		r2.setShortGI(rf.getG5ShortInterval());
		r2.setWmm(rf.getG5WmmEn());
		// r2.setRelateThreshold(rf.getG5WmmRelate());
		r2.setClients(rf.getG5Clients());
		list.add(0, r1);
		list.add(1, r2);
		params.put("Rf", list);
		return params;
	}

	private void updateRf(Rf or, Rf rf) {
		or.setName(rf.getName());
		or.setG24Bandwidth(rf.getG24Bandwidth());
		or.setG24BeaconInterval(rf.getG24BeaconInterval());
		or.setG24Bitrate(rf.getG24Bitrate());
		or.setG24Channel(rf.getG24Channel());
		or.setG24Clients(rf.getG24Clients());
		or.setG24En(rf.getG24En());
		or.setG24PowerLevel(rf.getG24PowerLevel());
		or.setG24PowerMode(rf.getG24PowerMode());
		or.setG24ShortInterval(rf.getG24ShortInterval());
		or.setG24ShortPreamble(rf.getG24ShortPreamble());
		or.setG24Standard(rf.getG24Standard());
		or.setG24WmmEn(rf.getG24WmmEn());
		or.setG24RomaingEn(rf.getG24RomaingEn());
		or.setG24WmmRelate(rf.getG24WmmRelate());
		or.setG24Roamingthreshold(rf.getG24Roamingthreshold());
		or.setG5Bandwidth(rf.getG5Bandwidth());
		or.setG5BeaconInterval(rf.getG5BeaconInterval());
		or.setG5VhtBandwidth(rf.getG5VhtBandwidth());
		or.setG5Channel(rf.getG5Channel());
		or.setG5Clients(rf.getG5Clients());
		or.setG5En(rf.getG5En());
		or.setG5PowerLevel(rf.getG5PowerLevel());
		or.setG5PowerMode(rf.getG5PowerMode());
		or.setG5ShortInterval(rf.getG5ShortInterval());
		or.setG5ShortPreamble(rf.getG5ShortPreamble());
		or.setG5Standard(rf.getG5Standard());
		or.setG5WmmEn(rf.getG5WmmEn());
		or.setG5RomaingEn(rf.getG5RomaingEn());
		or.setG5WmmRelate(rf.getG5WmmRelate());
		or.setG5Roamingthreshold(rf.getG5Roamingthreshold());
	}

	/**
	 * 
	 * @param deviceRf
	 * @param rf
	 */
	public void saveDeviceRf(CustomRf customRf, Rf rf) {
		customRf.setG24En(rf.getG24En());
		customRf.setG24Standard(rf.getG24Standard());
		customRf.setG24Bandwidth(rf.getG24Bandwidth());
		customRf.setG24Channel(rf.getG24Channel());
		customRf.setG24RomaingEn(rf.getG24RomaingEn());
		customRf.setG24Roamingthreshold(rf.getG24Roamingthreshold());
		customRf.setG24WmmRelate(rf.getG24WmmRelate());
		customRf.setG24Clients(rf.getG24Clients());
		customRf.setG5En(rf.getG5En());
		customRf.setG5Standard(rf.getG5Standard());
		customRf.setG5Bandwidth(rf.getG5Bandwidth());
		customRf.setG5VhtBandwidth(rf.getG5VhtBandwidth());
		customRf.setG5Channel(rf.getG5Channel());
		customRf.setG5RomaingEn(rf.getG5RomaingEn());
		customRf.setG5Roamingthreshold(rf.getG5Roamingthreshold());
		customRf.setG5WmmRelate(rf.getG5WmmRelate());
		customRf.setG5Clients(rf.getG5Clients());
	}

	/**
	 * 新增与编辑射频模板
	 */
	@Override
	@Transactional(rollbackFor = { Exception.class }, readOnly = false)
	@doLog(description = Tips.LogRfAddOrUpdate, key = { "#rf.name" })
	public RestResult edit(long userId, Rf rf) {
		RestResult result = new RestResult();
		int error = 1;
		String errMsg = messageSourceUtil.getMessage(Tips.OperationSucceed);
		if (checkRf(userId, rf)) {
			long id = rf.getId();
			if (id == 0) {
				rf.setUserId(userId);
				rfMapper.save(rf);
				error = 0;
			} else {
				Rf or = rfMapper.findById(id);
				Map<String, Object> params = new HashMap<String, Object>();
				if (or != null && or.getUserId() == userId && or.getId() == id) {
					updateRf(or, rf);
					rfMapper.update(or);
					// 修改之后，查找调用该射频的设备,如果有,下发生效
					params = saveParams(rf);// 需要下发的数据
					// 找到对应的设备
					long rfIds[] = { rf.getId() };
					List<Device> devices = deviceMapper.queryDeviceByRfIds(rfIds);
					deviceAliveOrNot(devices, params, false);
					error = 0;
				} else {
					errMsg = messageSourceUtil.getMessage(Tips.RfPermissionDenied);
				}
			}
		} else {
			errMsg = messageSourceUtil.getMessage(Tips.OperationFailed);
		}
		result.setErrorCode(error);
		result.setErrorMsg(errMsg);
		return result;
	}

	@Override
	public TableOutput<Rf> queryByCondition(TableInput input, long userId) {
		Map<String, Object> conditions = new HashMap<>();
		conditions.put("searchs", input.getSearch());
		conditions.put("userId", userId);
		if (input.getOrder() != null) {
			conditions.put("orderColumn", input.getOrder().getColumn());
			conditions.put("orderDirection", input.getOrder().getDir());
		}
		conditions.put("start", input.getStart());
		conditions.put("rows", input.getRows());
		List<Rf> rfs = rfMapper.queryConditions(conditions);
		int total = rfMapper.queryConditionsCount(conditions);
		TableOutput<Rf> output = new TableOutput<>();
		output.setTotal(total);
		output.setRows(input.getRows());
		output.setStart(input.getStart());
		output.setList(rfs);
		return output;
	}

	@Override
	@Transactional(rollbackFor = { Exception.class }, readOnly = false)
	@doLog(description = Tips.LogDeleteRf, key = { "" })
	public RestResult delete(long[] rfIds, long userId) {
		RestResult result = new RestResult();
		if (rfIds != null && rfIds.length > 0) {
			List<Rf> rfs = rfMapper.findByIds(rfIds);
			if (hasRights(rfs, userId)) {
				// 查询设备中是否引用了这些模板
				List<Device> device = deviceMapper.queryDeviceByRfIds(rfIds);
				if (device.size() > 0) {
					result.setErrorCode(2);
					result.setErrorMsg(messageSourceUtil.getMessage(Tips.RfNoDelete));
					return result;
				} else {
					rfMapper.delete(rfIds);
				}
			} else {
				result.setErrorCode(2);
				result.setErrorMsg(messageSourceUtil.getMessage(Tips.RfPermissionDenied));
				return result;
			}
		} else {
			result.setErrorCode(1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.InvalidParameter));
			return result;
		}
		result.setErrorMsg(messageSourceUtil.getMessage(Tips.OperationSucceed));
		return result;
	}

	@Override
	public boolean hasRights(List<Rf> rfs, long userId) {
		if (rfs != null) {
			for (Rf rf : rfs) {
				if (userId != rf.getUserId()) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	/**
	 * 查询设备是否在线并下发数据
	 * 
	 * @param devices
	 * @param userid
	 * @param params
	 * @return 在线下发，离线返回失败原因
	 */
	public RestResult deviceAliveOrNot(List<Device> devices, Map<String, Object> params, boolean flag) {
		RestResult result = new RestResult();
		String errorMsg = "";
		int errorCode = 0;
		if (devices.size() > 0) {
			for (Device device : devices) {
				long version = device.getVersion() + 1;
				device.setVersion(version);
				deviceMapper.update(device);
				if (device.getStatus() == 1) {// 设备在线
					if (device.getSystemMode() == 0) {// 瘦ap
						// 下发
						String topic = MqttDeviceClientConfig.router(device.getSn());
						Set msg = new Set();
						String msgId = UUID.randomUUID().toString().replaceAll("-", "");
						params.put("version", version);
						msg.setId(msgId);
						msg.setReplyTo(Token.getToken());
						msg.setCommit(false);
						msg.setData(params);
						try {
							if (flag) {
								rpcClient.callWithTimeout(topic, msg, 5);
							} else {
								rpcClient.send(topic, msg);
							}
							errorCode = 0;
							errorMsg += "";
						} catch (RPCException e) {
							e.printStackTrace();
							errorCode = 1;
							errorMsg += messageSourceUtil.getMessage(Tips.FailSn11).replaceAll("#", device.getSn())+ "</br>";
						}
					} else {
						errorCode = 1;
						errorMsg += messageSourceUtil.getMessage(Tips.RfConfig).replaceAll("#", device.getSn()) + "</br>";
					}
				} else {
					errorCode = 1;
					errorMsg += messageSourceUtil.getMessage(Tips.FailSn12).replaceAll("#", device.getSn()) + "</br>";
				}
			}
			
			
			String url = "http://" + httpDNSDiscoery.discover() + "/device/bind?";
			List<String> sns = devices.stream().map(Device::getSn).collect(Collectors.toList());
			for (String sn : sns) {
				url = url + "sns=" + sn + "&";
			}
			url = url.substring(0, url.length() - 1);
			final String url_ = url;
			Client client = new Client();
			if (TransactionSynchronizationManager.isActualTransactionActive()) {
	            TransactionSynchronizationManager
	                    .registerSynchronization(new TransactionSynchronizationAdapter() {
	                        @Override
	                        public void afterCommit() {
	                            // 事务提交后执行回调
	                        		client.doGetWithJson(url_);
	                        }
	                    });
	        } else {
	            // 事务提交后执行回调
				client.doGetWithJson(url);
	        }
			
		}
		if (errorMsg == "" || errorMsg.length() == 0) {
			errorMsg = messageSourceUtil.getMessage(Tips.CmdSuccess);
		}
		result.setErrorCode(errorCode);
		result.setErrorMsg(errorMsg);
		return result;
	}

	@Override
	@Transactional(rollbackFor = { Exception.class }, readOnly = false)
	@doLog(description = Tips.LogRf, key = { "" })
	public RestResult save(long userId, RfInput rfInput) {
		RestResult result = new RestResult();
		int error = 1;
		String errMsg = "";
		List<Long> deviceIds = rfInput.getDeviceId();
		Rf rf = rfInput.getRf();
		List<Device> devices = deviceMapper.queryDevicesByIds(deviceIds);
		Map<String, Object> params = new HashMap<String, Object>();
		if (devices.size() > 0) {
			if (rfInput.getType() == 1) {// 下发空配置
				params = new HashMap<String, Object>();
				params.put("Rf", "");
				error = 0;
				RestResult res = deviceAliveOrNot(devices, params, true);
				if (error == 0) {
					deviceMapper.updateDeviceRfsById(deviceIds, null);
					// 更新device_rf表
					customRfMapper.deleteByDeviceIds(deviceIds);
				}
				return res;
			} else if (checkRf(userId, rf)) {
				long id = rf.getId();
				if (id == 0) {// 自定义
					CustomRf customRf = new CustomRf();
					for (Device device : devices) {
						if (device != null && device.getSystemMode() == 0) {// 瘦ap
							customRf = customRfMapper.queryByDeviceID(device.getId());
							if (customRf == null) {// 不存在自定义数据，保存到device_rf表
								customRf = new CustomRf();
								saveDeviceRf(customRf, rf);
								customRf.setDeviceId(device.getId());
								customRfMapper.save(customRf);
							} else {// 若已经存在自定义,则需要更新device_rf表
								saveDeviceRf(customRf, rf);
								customRfMapper.update(customRf);
							}
							device.setRfId(null);
							deviceMapper.update(device);
							errMsg += "";
						} else {
							errMsg += messageSourceUtil.getMessage(Tips.RfConfig).replaceAll("#", device.getSn()) + "</br>";
							continue;
						}
					}
					params = saveParams(customRf);
					error = 0;
				} else {// 选择模板
					for (Device device : devices) {
						if (device != null && device.getSystemMode() == 0) {// 瘦ap
							device.setRfId(rf.getId());
							deviceMapper.update(device);
							// 更新device_rf表
							customRfMapper.delete(device.getId());
							errMsg += "";
						} else {// 胖ap
							errMsg += messageSourceUtil.getMessage(Tips.RfConfig).replaceAll("#", device.getSn()) + "</br>";
							continue;
						}
					}
					error = 0;
					params = saveParams(rf);// 需要下发的数据
				}
			}
			// 下发配置
			if (error == 0 && params.size() > 0) {
				RestResult res = deviceAliveOrNot(devices, params, true);
				error = res.getErrorCode();
				errMsg = res.getErrorMsg();
			}
		}
		result.setErrorCode(error);
		result.setErrorMsg(errMsg);
		return result;
	}

	@Override
	public RestResult updateRouter(Device router,String data,String oper) {
		RestResult result = new RestResult();
		String topic = MqttDeviceClientConfig.router(router.getSn());
		Set msg = new Set();
		String msgId = UUID.randomUUID().toString().replaceAll("-", "");
		msg.setId(msgId);
		msg.setReplyTo(Token.getToken());
		msg.setCommit(false);
		msg.setData(JSON.parseObject(data));
		try {
			Message messg =rpcClient.callWithTimeout(topic, msg, 5);
			System.out.println("messg: "+JSON.toJSONString(messg));
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.OperationSucceed));
		} catch (RPCException e) {
			e.printStackTrace();
			result.setErrorCode(1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.Error));
			return result;
		}
		return result;
	}
	
}
